package com.wmx.thread.concurrent;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.TimeUnit;

/**********************************
 * @author wmx
 * @date 2019/8/26 13:56
 * @description:
 * @version 1.0
 * CyclicBarrier是一个同步辅助类，它允许一组线程相互等待直到所有线程都到达一个公共的屏障点。
 * 在程序中有固定数量的线程，这些线程有时候必须等待彼此，这种情况下，使用CyclicBarrier很有帮助.
 * 这个屏障之所以用循环修饰，是因为在所有的线程释放彼此之后，这个屏障是可以重新使用的。
 *  CyclicBarrier(int parties)  parties 是参与线程的个数
 *  CyclicBarrier(int parties, Runnable barrierAction) 第二个构造方法有一个 Runnable 参数，这个参数的意思是最后一个到达线程要做的任务
 *
 *
 *
 * CyclicBarrier的简单理解

      其实，我更喜欢[人满发车]这个词来理解CyclicBarrier的作用：
      长途汽车站提供长途客运服务。
      当等待坐车的乘客到达20人时，汽车站就会发出一辆长途汽车，让这20个乘客上车走人。
      等到下次等待的乘客又到达20人是，汽车站就会又发出一辆长途汽车。


总结：CountDownLatch和CyclicBarrier都有让多个线程等待同步然后再开始下一步动作的意思，
     但是CountDownLatch的下一步的动作实施者是主线程，具有不可重复性；而CyclicBarrier的下一步动作实施者还是
“其他线程”本身，具有往复多次实施动作的特点。

 *
 *
 ************************************/
@Slf4j
public class CyclicBarrierExample {
    public static void main(String[] args) throws InterruptedException {
         //doSomething();
         doSomething1();

    }

    //测试CyclicBarrier(int parties) getParties() getNumberWaiting
    public static void doSomething()throws InterruptedException{
        CyclicBarrier barrier = new CyclicBarrier(2);
        //barrier.getParties()获取开启屏障的方数：
        log.info("【barrier.getParties()获取开启屏障的方数：】"+barrier.getParties());
        //通过barrier.getNumberWaiting()获取正在等待的线程数
        log.info("【通过barrier.getNumberWaiting()获取正在等待的线程数：】"+barrier.getNumberWaiting());

        new Thread(()->{
            log.info("添加第一个等待的线程===="+Thread.currentThread().getName());
            try {
                barrier.await();
                log.info(Thread.currentThread().getName() + " is running...");
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.info(Thread.currentThread().getName() + " is terminated...");

        }).start();

        TimeUnit.SECONDS.sleep(1);

        log.info("【通过barrier.getNumberWaiting()获取正在等待的线程数：】"+barrier.getNumberWaiting());

        new Thread(()->{
            log.info("添加第二个等待的线程===="+Thread.currentThread().getName());
            try {
                barrier.await();
                log.info(Thread.currentThread().getName() + " is running...");
            } catch (Exception e) {
                e.printStackTrace();
            }
            log.info(Thread.currentThread().getName() + " is terminated...");

        }).start();
        log.info("【通过barrier.getNumberWaiting()获取正在等待的线程数：】"+barrier.getNumberWaiting());

        //已经打开的屏障，再次有线程等待的话，还会重新生效--视为循环
        new Thread(() -> {
            log.info("屏障打开之后，再有线程加入等待：" + Thread.currentThread().getName());
            try {

                barrier.await();
                log.info(Thread.currentThread().getName() + " is running....");
            } catch (Exception e) {
                e.printStackTrace();
            }

            log.info(Thread.currentThread().getName() + " is terminated...");
        }).start();

        TimeUnit.SECONDS.sleep(1);
        log.info("通过barrier.getNumberWaiting()获取正在等待的线程数：打开屏障之后---" + barrier.getNumberWaiting());

        new Thread(() -> {
            log.info("屏障打开之后，再有线程加入等待：" + Thread.currentThread().getName());
            try {
                barrier.await();
                log.info(Thread.currentThread().getName() + " is running....");
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
            log.info(Thread.currentThread().getName() + " is terminated.");

        }).start();
        TimeUnit.SECONDS.sleep(1);
        log.info("通过barrier.getNumberWaiting()获取正在等待的线程数：打开屏障之后---" + barrier.getNumberWaiting());

    }

    //测试CyclicBarrier(int parties ,Runnable runnable)
    public static void doSomething1(){
         CyclicBarrier cyclicBarrier = new CyclicBarrier(2, new Runnable() {
             @Override
             public void run() {
                 log.info("【最后到达Parties开始做事】"+Thread.currentThread().getName());
             }
         });
        for (int i = 0; i <2 ; i++) {
             new Thread(()->{
                 try {
                     TimeUnit.SECONDS.sleep(1);
                     log.info("添加一个等待线程======"+Thread.currentThread().getName());
                     cyclicBarrier.await();
                     log.info("==============第一次Parties屏障打开后=============");
                     TimeUnit.SECONDS.sleep(2);
                     log.info("再次========添加第一个等待线程======"+Thread.currentThread().getName());
                     cyclicBarrier.await();
                     log.info("再次==============Parties屏障打开后=============");

                 } catch (InterruptedException e) {
                     e.printStackTrace();
                 } catch (BrokenBarrierException e) {
                     e.printStackTrace();
                 }


             }).start();
        }
    }


}
